
package asd; 

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 *
 * @author Robert & Sejk
 */


public class DataFlow {


	private int asdy;
	private Data d;

    public DataFlow() {}

    //funkcja zwraca kod potrzebnej funkcji, do dopracowania jeszcze
    public String GetFunctionText(String FunName, String FileName) {
        String[] tmp = SearchingFunctionSourceCode(FunName, FileName);
        String fun_text = "";
        for (int i = 0; i < tmp.length; i++) {
            fun_text = fun_text + tmp[i] + "\n";
        }
        return fun_text;
    }

    //funkcja usuwajaca z kodu wczytanej funkcji białe znaki
    public String CleanFunctionText(String FunText) {
        FunText = FunText.trim();
        String NewText = "";
        int i, zp;
        char ch;

        for (i = 0; i <= FunText.length() - 1; i++) {
            ch = FunText.charAt(i);
            zp = (int) ch;
            if (zp > 32) {
                NewText = NewText + FunText.charAt(i);
            }
        }
        return NewText;
    }
	private int dupa;
    public IsNewLineChar(char ch) {
        if ((ch == '{') || (ch == '}') || (ch == ';')) {
            return true;
        } else {
            return false;
        }
    }
	
    //funkcja zwraca koleją linię kodu - licznik (LineNo) sztuczny
    //zwraca "error" jezeli szukamy w lini ktorej juz nie ma
     public String ReadFunctionLine(String FunText, int LineNo)
    {
        String LineText = "", NewText = "";
        char z, ch;
        int i, j, LineCount, zp;
        LineCount = 0;

        for (j = 0; j <= FunText.length()-1; j++)
        {
            z = FunText.charAt(j);
            if (IsNewLineChar(z)) LineCount++;
        }
        if ((LineNo > LineCount)) return "error";

        LineCount=0;
        for (j = 0; j <= FunText.length()-1; j++)
        {
            z = FunText.charAt(j);
            if (IsNewLineChar(z)) LineCount++;
            if (LineNo == 0) LineText=LineText + z;
            if (LineCount == LineNo)
                for (i = j + 1; i < FunText.length(); i++)
                {
                    z = FunText.charAt(i);
                    if (!IsNewLineChar(z)) LineText = LineText + z;
                        else return LineText;
                }
        }
        return LineText;
    }


    public boolean IsKeyWord(String expression) {
        String keyword = "abstract boolean break byte case cast catch char class void ";
        keyword = keyword + "cons continue default do double else extends volatile ";
        keyword = keyword + "final finally float for future generic goto if while ";
        keyword = keyword + "inner instanceof in interface long native new null ";
        keyword = keyword + "implements import operator outer package private virtual ";
        keyword = keyword + "protected public rest return short static super switch ";
        keyword = keyword + "synchronized this throw throws transient try var unsigned ";

        char ch;
        int index = keyword.indexOf(expression);
        if (index == -1) {
            return false;
        } else {
            ch = keyword.charAt(index - 1);
            if (isLetterOrDigit(ch)) {
                return false;
            }
            ch = keyword.charAt(index + expression.length());
            if (isLetterOrDigit(ch)) {
                return false;
            }
            return true;
        }
    }

    //funkcja pomocnicza, sprawdza czy znak jest litera lub cyfra
    //ehh.. takie cos jest niby w java.lang.Character, ale coś nie działa :(
    public boolean isLetterOrDigit(char ch) {
        int asci = (int) ch;
        if (((asci >= 48) && (asci <= 57)) || //liczby
                ((asci >= 65) && (asci <= 90)) || //duże litery
                ((asci >= 97) && (asci <= 122))) //małe litery
        {
            return true;
        } else {
            return false;
        }
    }

    //funkcja sprawdza czy w linii jest uzyta zmienna
    //sprawdza czy to napewno ona (np. szukamy 'uto', wiec 'auto' nas nie interesuje
    //edit: funkcja zamiast boolean zwraca inta - jezeli jest w lini to zwraca
    //index poczatku wystapienia, jezeli nie ma to zwraca -1
   public int CheckVarInLine(String Line, String VarName, int startIndex)
    {
        int index;
        char przed= 'x',po= 'x';
        boolean sprawdzPrzed= true, sprawdzPo= true;
        boolean PrzedJestLC= false, PoJestLC= false;

        index = Line.indexOf(VarName, startIndex);

        if (index==-1) return index;

        if (index==0) sprawdzPrzed = false;
        if (index+VarName.length()>=Line.length()) sprawdzPo=false;

        if (sprawdzPrzed)
        {
            przed=Line.charAt(index-1);
            PrzedJestLC= isLetterOrDigit(przed);
        }
        if (sprawdzPo)
        {
            po= Line.charAt(index+VarName.length());
            PoJestLC= isLetterOrDigit(po);
        }

        if ((PrzedJestLC) || (PoJestLC))  index= CheckVarInLine(Line, VarName, index+1);

        return index;
    }


    public String[] FileReader(String fileName) {
        String[] ret = new String[2000];
        try {
            BufferedReader in = new BufferedReader(new FileReader(fileName));
            String tmp;
            int i = 0;
            while ((tmp = in.readLine()) != null) {
                ret[i] = tmp;
                i++;
            }
            in.close();
        } catch (IOException e) {
            System.out.println("File not found");
        }
        return ret;
    }

    //funkcja szukajaca funkcji w pliku wktórej jest wybrany argument
    //funckja zapisuje kod do tablicy string
    public String[] SearchingFunctionSourceCode(String FunName, String FileName) {
        String[] file_tmp = FileReader(FileName);

        //Pattern p = Pattern.compile("(.*public.*|.*private.*)" + FunName + ".*");
        int start=0;
        int end=0;
        int num_of_starts = 0;
        int num_of_ends = 0;
        for (int i = 0; i < file_tmp.length; i++) {
            if (file_tmp[i] != null) {
                file_tmp[i] = file_tmp[i].trim();
                if (file_tmp[i].matches("(public|private|protected|.* )" + FunName + ".*"))
                {
                    start = i;
                    //System.out.println(file_tmp[i]+ " ");
                }
                int in = file_tmp[i].indexOf("{");
                if (in != -1 && start !=0) {
                    num_of_starts++;
                }
                in = file_tmp[i].indexOf("}");
                if (in != -1 && start !=0) {
                    num_of_ends++;
                }
                if (num_of_starts == num_of_ends && num_of_starts>0 && num_of_ends>0)
                {
                    end = i;
                    break;
                }
            }
        }
        System.out.println(num_of_starts + " " + num_of_ends + " " + start + " " + end);
        String[] result = new String[end - start+1];
        for (int i = 0; i < result.length; i++) {
            result[i] = file_tmp[i+start];
            System.out.println(result[i]);
        }
        return result;
    }

    //funkcja ma sprawdzac czy funkcja zostala utworzona przez programiste
    //przyjmuje nazwe funkcji
    //zwraca nazwe pliku w ktorym znajduje sie funkcja
    //UWAGA! dane bierze z tablicy funkcji ktore dostaje z umla (czego jeszcze nie ma)
    //UWAGA! sprawdza takze includy zastosowane w kodzie aktualnie przetwazanym
    //to jest dopiero do zrobienia! czekamy na inicjatywe czesci umlowej!
    public String IsUserFunction(String FunName) {

        return "a";
    }

    //funkcja zwraca nazwe funkcji ktora w linii jest wywolana
    //działa tylko dla prostych przypadkow (np. t.StrToInt(i,a)
    //narazie ma wyciagac calosc (tylko to co jest poza nawiasem)
    public String GetFunctionCall(String Line) {
        char c;
        String tmp = "";
        for (int i = 0; i < Line.length(); i++) {
            c = Line.charAt(i);
            if (c == '(') {
                break;
            } else if ((isLetterOrDigit(c) || c == '.')) {
                tmp = tmp + Line.charAt(i);
            }
        }
        if (!IsKeyWord(tmp)) {
            return tmp;
        } else {
            return "";
        }
    }

    //funkcja sprawdza czy w lini wystepuje przypisanie
    // zwraca index gdzie ono jest lub -1 gdy go nie ma
    // lub zwraca -2 gdy kod zawiera bledy!
    public int IsAssignment(String Line) {
        int index = Line.indexOf('=');
        if (index == -1) {
            return index;
        }
        if ((index == 0) || (index == Line.length())) {
            return -2;                    //obsługa błędnego kodu
        }
        if ((Line.charAt(index + 1) == '=') || (Line.charAt(index - 1) == '=')) {
            return -1;
        }
        return index;
    }

    //sprawdza czy wywolana funkcja jest z uzywanego objektu czy innego
    public boolean IsThisClassFunction(String expression) {
        int index = expression.indexOf('.');
        if (index == -1) {
            return false;
        } else {
            if (GetObjectName(expression).compareTo("this") == 0) {
                return true;
            } else {
                return false;
            }
        }
    }

    //funkcja z wywolania funkcji zwraca nazwe funckji
    public String GetFunctionName(String expression) {
        int i = expression.length() - 1;
        String tmp = "", tmp1 = "";

        while ((expression.charAt(i) != '.') && (i >= 0)) {
            tmp = tmp + expression.charAt(i);
            i--;
        }

        for (i = tmp.length() - 1; i >= 0; i--) {
            tmp1 = tmp1 + tmp.charAt(i);
        }

        return tmp1;
    }

    //funkcja z wywołania funkcji zwraca nazwe objektu
    //objekt nalezy dopasowac do klasy z wczesniejszych deklaracji
    public String GetObjectName(String expression) {
        int i = expression.length() - 1;
        String tmp = "", tmp1 = "";
        while ((expression.charAt(i) != '.') && (i >= 0)) {
            i--;
        }
        i--;

        while (i >= 0) {
            tmp = tmp + expression.charAt(i);
            i--;
        }

        for (i = tmp.length() - 1; i >= 0; i--) {
            tmp1 = tmp1 + tmp.charAt(i);

        }
        return tmp1;
    }

    //funkcja wyciaga nazwy uzywanych klas w pliku na postwaie importów
    public String[] GetClassesNames(String FileName) {

        String[] result = new String[10];
        return result;
    }

    //funkcja znajduje w kodzie typ zmiennej
    //UWAGA! funkcja dobiera sie do pierwszej deklaracji
    //trzeba bedzie to poprawic, ale to pozniej :)
    public String FindVarType(String VarName, String FunText)
    {

        // najpierw sprawdzamy czy w klasie nie ma deklaracji
        // a do tego potrzebujemy umla

        String tmp="";
        int i = 0, index = 0, zp;
        String LineText;

        LineText = ReadFunctionLine(FunText, i);
        while ((LineText.compareTo("error")!=0))
        {
            index = CheckVarInLine(LineText, VarName, 0);
            if (index != -1)
            {
                zp = LineText.indexOf('(');
                if ((zp<index) && (zp!=-1)) tmp = LineText.substring(zp+1,index);
                   else tmp = LineText.substring(0,index);
                tmp = CleanFunctionText(tmp);
                return tmp;
            }
            
            i++;
            LineText = ReadFunctionLine(FunText, i);
        }
        return "error";
    }
	
	
	public String POZDRO6000000000000000000() {
            return "POZDRO";
    }
	
	

    //funckja zwraca mapę przepływu dla wybranej zmiennej
    //zmienna dostajemy od Michała (on wywołuje funkcje)
    //narazie zakomentowany schemat calosci
    public void GetMapOfVariableFlow(String VarName, String FunName, 
	String ClassName, String FileName)
    {

        String tmp="";
        int i = 0, index = 0;        

        String FunText = GetFunctionText(FunName, FileName);
        System.out.println(FunText);

        String FunTextClean = CleanFunctionText(FunText);
        String  LineText = ReadFunctionLine(FunTextClean, i);
        
        while ((LineText.compareTo("error")!=0))
        {
            i++;
            LineText = ReadFunctionLine(FunTextClean, i);
            //System.out.println(LineText);
            index = CheckVarInLine(LineText, VarName, 0);
            
            if (index != -1)
            {    
                //wypisanie przeplywu
                //System.out.println(LineText);
                //System.out.println(GetFunctionCall(LineText));
                //System.out.println(GetFunctionName(LineText));
                //tutaj sprawdzamy cos sie dzieje w linii - najwazniejsza czesc
                //ja bym to wywalil do innej funkcji zeby nie smiecic
                //no i tutaj w sumie tworzymy mape xD
            }
        }
    }

    //main prezentacyjny
    public static void main(String[] args)
    {
        DataFlow d = new DataFlow();
        String FunName = "GetClassesNames";
        String FileName = "DataFlow.java";
        d.SearchingFunctionSourceCode(FunName, FileName);
        //String FunText = d.GetFunctionText(FunName, FileName);
        //System.out.println("Przeplyw arg Integer i w funkcji AddToInt");
        //d.GetMapOfVariableFlow("i", FunName, null, FileName);
        //String tmp = d.FindVarType("t", FunText);
        //System.out.println(tmp);
    }

}

public class DataFlow2 {
	
    private Vector klasy;
	
		

}

